# file name: app/network_monitor/collector/zabbix_collector.py
from typing import List, Dict
import time
from modules.zabbix_utils.utils.zabbix_client import ZabbixClient
from .base_collector import BaseDataCollector
from modules.blk.cmdb.cmdb_service import CMDBService
from app.network_monitor.config.config import ZABBIX_CONFIG


class ZabbixCollector(BaseDataCollector):
    """Concrete collector implementation for Zabbix monitoring system.

    Collects alerts from Zabbix servers using the Zabbix API.
    """

    def __init__(self):
        """Initialize the Zabbix collector."""
        self._zabbix_servers = self._load_zabbix_servers()
        self._username = ZABBIX_CONFIG["username"]
        self._password = ZABBIX_CONFIG["password"]

    def get_source_type(self) -> str:
        """Get the Zabbix source type identifier.

        Returns:
            str: Always returns 'zabbix'
        """
        return "zabbix"

    def collect_raw_alerts(self) -> List[Dict]:
        """Collect all active problems from all configured Zabbix servers.

        Returns:
            List[Dict]: A list of raw Zabbix problem dictionaries.
        """
        raw_alerts = []

        for server in self._zabbix_servers:
            try:
                alerts = self._collect_from_server(server)
                raw_alerts.extend(alerts)
            except Exception as e:
                error_alert = self._create_error_alert(server, str(e))
                raw_alerts.append(error_alert)

        return raw_alerts

    def _load_zabbix_servers(self) -> List[Dict]:
        """Load Zabbix server configurations from CMDB.

        Returns:
            List[Dict]: List of Zabbix server configurations
        """
        data = CMDBService().select("zabbix_docker_info")
        return data["data"]["info"]

    def _collect_from_server(self, server_info: Dict) -> List[Dict]:
        """Collect problems from a single Zabbix server.

        Args:
            server_info: Dictionary containing server connection info

        Returns:
            List[Dict]: Problems from this server
        """
        client = ZabbixClient(
            ip=server_info["docker_server_ip"],
            port=server_info["docker_server_port"],
            username=self._username,
            password=self._password,
        )

        hosts = self._get_problem_hosts(client)
        if not hosts:
            return []

        problems = []
        for host in hosts:
            host_problems = self._get_host_problems(client, host["hostid"])
            for problem in host_problems:
                problem.update(
                    {
                        "zabbix_ip": client.ip,
                        "zabbix_port": client.port,
                        "host_name": host["name"],
                    }
                )
            problems.extend(host_problems)

        return problems

    def _get_problem_hosts(self, client: ZabbixClient) -> List[Dict]:
        """Get all hosts that currently have problems.

        Args:
            client: ZabbixClient instance

        Returns:
            List[Dict]: Hosts with problems
        """
        template = client.get_template("problems", "hosts_with_problems")
        return client.fetch(template)

    def _get_host_problems(self, client: ZabbixClient, hostid: str) -> List[Dict]:
        """Get all active problems for a specific host.

        Args:
            client: ZabbixClient instance
            hostid: ID of the host to check

        Returns:
            List[Dict]: Active problems for this host
        """
        template = client.get_template("problems", "get")
        template["params"]["hostids"] = hostid
        problems = client.fetch(template)
        return [
            p for p in problems if p["r_eventid"] == "0"
        ]  # Filter out recovered problems

    def _create_error_alert(self, server_info: Dict, error: str) -> Dict:
        """Create an error alert when connection to server fails.

        Args:
            server_info: Server connection info
            error: Error message

        Returns:
            Dict: Error alert dictionary
        """
        return {
            "clock": str(int(time.time())),
            "name": f"Connection failed to {server_info['docker_server_ip']}:{server_info['docker_server_port']} - {error}",
            "acknowledged": "0",
            "severity": "3",
            "zabbix_ip": server_info["docker_server_ip"],
            "zabbix_port": server_info["docker_server_port"],
            "host_name": server_info["docker_server_ip"],
        }
